#include "mvc/view/view.h"
#include "mvc/model/model.h"
#include "mvc/view/principal_window.h"
#include "mvc/view/main_dialog.h"
#include "mvc/view/param_widget_uav.h"
#include "mvc/view/param_widget_conventional.h"
#include "mvc/view/geometries_widget.h"
#include "mvc/view/opengl_widget.h"
#include "mvc/view/configuration_dialog.h"
#include "mvc/view/airfoil_dialog.h"
#include "mvc/view/analisis_dialog.h"
#include "mvc/view/settings_dialog.h"
#include "common/texture_indexs.h"
#include "common/exceptions.h"
#include <common/types.h>
#include "common/settings.h"
#include "common/modules.h"
#include "common/log/QsLog.h"

#include <iostream>

#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QProgressDialog>
#include <QApplication>


extern QMainWindow *mainWin;
extern QApplication *app;

View::View(QObject *parent) : QObject(parent)
{
    _principal_window = new Principal_window(0);

    _principal_window->move(QPoint(50, 50));
    connect(_principal_window, SIGNAL(s_new_project()), this, SLOT(new_project()));
    connect(_principal_window, SIGNAL(s_open_project(QString)), this, SLOT(open_project(QString)));
    connect(_principal_window, SIGNAL(s_close(QCloseEvent *)), this, SLOT(close_project(QCloseEvent *)));
    connect(_principal_window, SIGNAL(s_settings()), this, SLOT(settings()));
    connect(_principal_window, SIGNAL(s_english()), this, SLOT(set_english()));
    connect(_principal_window, SIGNAL(s_spanish()), this, SLOT(set_spanish()));
    connect(_principal_window, SIGNAL(s_graphicGeometry()), this, SLOT(graphic_geometry()));
    connect(_principal_window, SIGNAL(s_graphicAllConfigurations()), this, SLOT(graphic_all_configurations()));
    current_configuration = 1;


    _main_dialog = NULL;
    _geometries_widget = NULL;
    _param_widget_uav = NULL;
    _param_widget_conventional = NULL;
    _configuration_dialog = NULL;
    _settings_dialog = NULL;
    _serializer = NULL;
}

View::~View()
{
    delete _principal_window;
    clean_view();
}

// PUBLIC SLOTS


/**
  * Create a main dialog to make a new configuration.
  */
void View::new_project()
{
    if(ok_to_continue())
    {
        clean_view();
        _main_dialog = new Main_dialog(_principal_window);
        connect(_main_dialog, SIGNAL(s_new_project(int)), this, SLOT(new_project_module(int)));
        _main_dialog->show();
    }
}

/**
  * Create a new project of a specified configuration
  * module - the type of configuration
  */
void View::new_project_module(int module)
{
    //QLOG_INFO() << "new project " << get_module_key(module);

    _main_dialog->hide();

    QString _projects = projects_directory();

    QString filters = QString(".").append(QString(get_module_key(module)));
    QString file_name = QFileDialog::getSaveFileName(0, tr("New Project"), _projects, filters);

    //    file_name = QFileDialog::getSaveFileName(0, tr("New Project"), _projects, tr("uav project (*.uav)"));

    file_name.remove(0, file_name.lastIndexOf("projects/") + 9);

#ifdef _WIN32
    file_name.remove(file_name.lastIndexOf("."),file_name.length());
#endif

    if(!file_name.isEmpty())
    {
        if(!_main_dialog)
            delete _main_dialog;

        QString module_s;

        if(module == get_module_value(uavs_jw_module))
        {
            _serializer = new Aircraft_Serializer();

            _param_widget_uav = new Param_widget_uav(0);

            connect(_param_widget_uav, SIGNAL(s_load_parameters(ParametersWidget *, Airfoils_curve_map *, int )),
                    this, SLOT(load_parameters(ParametersWidget *, Airfoils_curve_map *, int )));

            module_s = "uav";

            _principal_window->add_central_widget(_param_widget_uav);
        }
        else if(module == get_module_value(conventional_w_module))
        {
            _serializer = new Aircraft_Serializer();

            _param_widget_conventional = new Param_widget_conventional(0);

            connect(_param_widget_conventional, SIGNAL(s_load_parameters(ParametersWidget *, Airfoils_curve_map *, int )),
                    this, SLOT(load_parameters(ParametersWidget *, Airfoils_curve_map *, int )));

            module_s = "conventional";

            _principal_window->add_central_widget(_param_widget_conventional);
        }
        else if(module == get_module_value(bwb_module))
        {
            QMessageBox warningMessage;

            warningMessage.setIconPixmap(QPixmap(":/images/Rocket.png"));
            warningMessage.setText(tr("This module isn't implemented"));
            warningMessage.exec();
            //QMessageBox::warning(0, tr("Info"),  , QMessageBox::Ok);

            module_s = "bwb";
        }

        _principal_window->setWindowTitle(file_name);

        emit s_new_project(file_name, module_s);
    }
    else
        _main_dialog->show();
}

/**
  *
  */
void View::load_parameters(ParametersWidget *parameters, Airfoils_curve_map *airfoil_point_list, int module)
{

    if(_param_widget_uav)
    {
        _param_widget_uav->close();
        delete _param_widget_uav;
        _param_widget_uav = NULL;
    }
    else if(_param_widget_conventional)
    {
        _param_widget_conventional->close();
        delete _param_widget_conventional;
        _param_widget_conventional = NULL;
    }

    emit s_load_parameters(parameters, airfoil_point_list, module);
}

/**
  * Open an existing project
  * project_name - the name of the proejct to open.
  */
void View::open_project(const QString &project_name)
{
    //std::cout << " TODO: open project "<< project_name.toStdString() << std::endl;
    if(ok_to_continue())
    {
        clean_view();
        QString file_name = QString(project_name).remove(0, project_name.lastIndexOf("projects/") + 9);

        QString module = QString(project_name).remove(0, project_name.lastIndexOf(".") + 1);

        if(get_module_value(module) == get_module_value(uavs_jw_module)
                || get_module_value(module) == get_module_value(conventional_w_module))
            _serializer = new Aircraft_Serializer();

        emit s_open_project(file_name, get_module_value(module));
    }

}

/**
  * close the current project
  **/
void View::close_project(QCloseEvent *ev)
{
    if(ok_to_continue())
        ev->accept();
    else
        ev->ignore();
}

/**
  *
  */
void View::simulate_pressed(int configuration)
{
    current_configuration = configuration;
    emit(s_load_configuration(configuration));
}


/**
  *
  */
void View::simulate_configuration(configurations_parameters_uavs *cpu, bool file_exist){
    _configuration_dialog = new Configuration_dialog();
    if (file_exist)
        _configuration_dialog->set_values(cpu);
    connect(_configuration_dialog, SIGNAL(s_load_configurations_parameters(configurations_parameters_uavs *)),
            this, SLOT(send_simulate_info(configurations_parameters_uavs *)));
    _configuration_dialog->show();

}

/**
  *
  */
void View::send_simulate_info(configurations_parameters_uavs *cpu)
{
    _configuration_dialog->close();
    emit s_simulate(current_configuration, cpu);

}

/**
  *
  */
void View::send_draw_configuration(int configuration){
    current_configuration = configuration;
    _principal_window->enable_view_actions();
    emit s_draw_configuration(configuration);
}

/**
  * Start or pause the Simulation
  */
void View::play_pause(){
    //    std::cout << "play/pause en el view" << std::endl;
    emit s_play_pause(current_configuration);
}

/**
  * Rewind Simulation to time 0.
  */
void View::rewind(){
    //    std::cout << "rewind en el view" << std::endl;
    emit s_rewind(current_configuration);
}

/**
  * Show the settings widget
  */
void View::settings(){
    _settings_dialog = new Settings_dialog (_principal_window);
    _settings_dialog->show();
}

/*
 * Actions when Spanish language is selected
 */
void View:: set_spanish(){
    spanishTranslator.load("uavs_es_AR", qApp->applicationDirPath()+"/languages");
    app->installTranslator(&spanishTranslator);
    retranslateUIs();
}

/*
 * Actions when English language is selected
 */
void View:: set_english(){
    app->removeTranslator(&spanishTranslator);
    retranslateUIs();
}

/**
 * @brief View::graphic_geometry
 */
void View::graphic_geometry()
{
    //current_configuration = _geometries_widget->get_drawed_configuration();
    Analisis_dialog *dialog = new Analisis_dialog;

//    Configuration *c = _model->get_configuration(current_configuration);

//    QMap<QString, QVector<double> > values;
//    _serializer->read_loadsfiles("/home/matias/gepar_ws/projects/sim/RID001", "GePar_loadsUAV.AUX",
//                                 &values);

    dialog->show();
}

/**
 * @brief View::graphic_all_configurations
 */
void View::graphic_all_configurations()
{
    Analisis_dialog *analisis_dialog = new Analisis_dialog;

    int total_configurations = _model->total_configurations();

    QVector<QString> coefficients;

    QString fst_config = _model->current_project().get_config_dir(1);

    _serializer->read_coefficients_loadfiles(fst_config, "GePar_loadsUAV.AUX", &coefficients);

    QPair<QString, QString> *_pair = _model->get_analysis_parameters().first();

    // For now just one variable, so intervals.size == 1
    analisis_dialog->set_domain_variable(_pair->second);
    analisis_dialog->set_image_variables(coefficients);

    for(int i = 0; i < total_configurations; i++)
    {
        QMap<QString, QVector<double> > values;
        QString current_config = _model->current_project().get_config_dir(i + 1);
        _serializer->read_loadsfiles(current_config, "GePar_loadsUAV.AUX", &values);

        double d_value = _model->get_configuration(i + 1).get_parameters()[_pair->first][_pair->second];
        analisis_dialog->add_values(d_value, values);
    }

    analisis_dialog->show();
}



// PUBLIC METHODS

/**
  * Return the principal window
  */
Principal_window *View::get_principal_window()
{
    return _principal_window;
}

/**
  * Set the model component
  */
void View::set_model(Model *model)
{
    _model = model;
}

/**
  * Changes the view component when the model change.
  */
void View::on_update(const Configuration *config)
{
    model_state c_state = _model->get_state();

    if(not stored_configurations.at(config->get_id() - 1))
    {
        try
        {
            QLOG_INFO() << "To Store: " << config->get_id();
            _serializer->write_points_to_datfiles(c_state.c_path, config);
            stored_configurations.setBit(config->get_id() - 1   , true);
        }
        catch(const Serializer_write_exception &e)
        {
            QMessageBox::warning(0, tr("Warning"), tr(e.what().toStdString().c_str()) , QMessageBox::Ok);
        }
    }

    if(c_state.to_load_simulation)
    {
        QVector<time_zone *> zones;

        QProgressDialog p(mainWin);
        p.setLabelText("Start loading simulation...");
        p.setRange(0, c_state.total_steps);
        p.setModal(true);
        for(int c_time = 0; c_time < c_state.total_steps; c_time++)
        {

            p.setLabelText(QString(tr("Loading step: %1")).arg(c_time + 1).append("/%1").arg(c_state.total_steps));
            p.setValue(c_time);
            app->processEvents();

            try
            {
                time_zone *c_tzone = _serializer->read_wake_zones(c_state.c_path, c_time + 1, c_state.st_scale);
                zones.push_back(c_tzone);
            }
            catch (Serializer_read_exception &e)
            {
                QMessageBox::warning(0, tr("Warning"), tr(e.what().toStdString().c_str()) , QMessageBox::Ok);
            }
        }

        emit s_add_simulation_zones_to_model(config->get_id(), zones);
    }

    _geometries_widget->draw_configuration(config, c_state.draw_simulation, c_state.st_step);
}

/**
  * Create the configurations in the geometries_widget to show all the values.
  */
void View::show_configs(QVector<Parameters *> values)
{
    //    std::cout << "TODO: On Show Configs" << std::endl;
    _geometries_widget = new Geometries_widget(_principal_window);
    connect(_geometries_widget, SIGNAL(s_draw_configuration(int)), this, SLOT(send_draw_configuration(int)));
    connect(_geometries_widget, SIGNAL(s_simulate_configuration(int)), this, SLOT(simulate_pressed(int)));
    connect(_principal_window, SIGNAL(s_rrotate()), _geometries_widget, SLOT(rrotate()));
    connect(_principal_window, SIGNAL(s_lrotate()), _geometries_widget, SLOT(lrotate()));
    connect(_principal_window, SIGNAL(s_urotate()), _geometries_widget, SLOT(urotate()));
    connect(_principal_window, SIGNAL(s_drotate()), _geometries_widget, SLOT(drotate()));
    connect(_principal_window, SIGNAL(s_zin()), _geometries_widget, SLOT(zin()));
    connect(_principal_window, SIGNAL(s_zout()), _geometries_widget, SLOT(zout()));
    connect(_principal_window, SIGNAL(s_rmove()), _geometries_widget, SLOT(rmove()));
    connect(_principal_window, SIGNAL(s_lmove()), _geometries_widget, SLOT(lmove()));
    connect(_principal_window, SIGNAL(s_dmove()), _geometries_widget, SLOT(dmove()));
    connect(_principal_window, SIGNAL(s_umove()), _geometries_widget, SLOT(umove()));
    connect(_principal_window, SIGNAL(s_reset_camera()), _geometries_widget, SLOT(reset_camera()));
    connect(_principal_window, SIGNAL(s_play_pause()), this, SLOT(play_pause()));
    connect(_principal_window, SIGNAL(s_rewind()), this, SLOT(rewind()));
    connect(_principal_window, SIGNAL(s_uavtex()), _geometries_widget, SLOT(uavtex()));
    connect(_principal_window, SIGNAL(s_simtex()), _geometries_widget, SLOT(simtex()));
    connect(_principal_window, SIGNAL(s_perspective()), _geometries_widget, SLOT(perspective()));
    connect(_principal_window, SIGNAL(s_ortho()), _geometries_widget, SLOT(ortho()));

    stored_configurations.resize(values.size());
    for(int i = 0; i < values.size(); i++)
        _geometries_widget->create_configuration(i + 1, values[i]);
    _geometries_widget->set_configuration_type(get_module_value(uavs_jw_module));

    int uav_tex = _geometries_widget->add_texture(new Uav_texture(tr("GREY")));
    int sim_tex1 = _geometries_widget->add_texture(new Uav_texture(tr("GREEN")));
    int sim_tex2 = _geometries_widget->add_texture(new Uav_texture(tr("BLUE")));
    int sim_tex3 = _geometries_widget->add_texture(new Uav_texture(tr("RED")));

    add_texture(tr("GREY"), uav_tex);
    add_texture(tr("GREEN"), sim_tex1);
    add_texture(tr("BLUE"), sim_tex2);
    add_texture(tr("RED"), sim_tex3);

    _principal_window->add_central_widget(_geometries_widget);
}

/**
  * @param aifroils - represents the airfoils info. Airfoil - Airfoil.dat
  */
Airfoils_curve_map *View::get_airfoils_list_point(QMap<QString, QString> airfoils)
{
    Airfoils_curve_map *airfoilist = new Airfoils_curve_map;

    Param_widget_uav *_pw = new Param_widget_uav(0);

    QList<QString> keys = airfoils.keys();
    for(int i = 0; i < airfoils.size(); i++)
    {
        QString c_airfoil_path = QString(airfoils_directory()).append(airfoils[keys.at(i)]);

        _pw->get_airfoil_dialog()->calc_reference_curve(c_airfoil_path);

        QVector<Point *> arf = _pw->get_airfoil_dialog()->get_reference_curve();

        airfoilist->insert(keys.at(i), arf);
    }

    delete _pw;

    return airfoilist;
}

/**
  *
  */
void View::clean_view()
{
    //    QLOG_INFO() << "TODO: View::clean_view";
    delete _main_dialog;
    delete _geometries_widget;
    delete _configuration_dialog;
    delete _settings_dialog;
    delete _serializer;
}

/**
 * @brief View::enable_graphic_all_configuration
 */
void View::enable_graphic_all_configuration()
{
    _principal_window->enable_graphic_allc();
}

//
// Private Methods
//

/**
  * Returns true if all condigurations are generated.
  */
bool View::ok_to_continue()
{
    //cout << "TODO: View.ok_to_continue" << endl;
    if(not _model->is_allc_generated())
    {
        int r = QMessageBox::warning(_principal_window, tr("Warning"),
                                     tr("Some configurations were not generated.\n"
                                        "Generate them before exiting?"),
                                     QMessageBox::Yes | QMessageBox::Default, QMessageBox::No,
                                     QMessageBox::Cancel | QMessageBox::Escape);
        if(r == QMessageBox::Yes)
        {
            emit s_save_project();
            return true;
        }
        else if(r == QMessageBox::Cancel)
            return false;
    }
    return true;
}

/*
 *
 */
void View::retranslateUIs(){
    _principal_window->retranslateUi();
    if (_geometries_widget != NULL){
        std::cout << "geometries widget ventana no null" << std::endl;
        if (!_geometries_widget->getClosed() ){
            std::cout << "ventana no cerrada" << std::endl;
            _geometries_widget->retranslateUi();
        }
    }
    if (_param_widget_uav != NULL){
        std::cout << "param widget uav ventana no null" << std::endl;
        if (!_param_widget_uav->getClosed()){
            std::cout << "ventana no cerrada" << std::endl;
            _param_widget_uav->retranslateUi();
        }
    }
    if (_param_widget_conventional != NULL){
        if (!_param_widget_conventional->getClosed()){
            std::cout << "ventana no cerrada" << std::endl;
            _param_widget_conventional->retranslateUi();
        }
    }
    if (_configuration_dialog != NULL){
        std::cout << "confg dialog ventana no null" << std::endl;
        if (!_configuration_dialog->getClosed()){
            std::cout << "configurt dialog ventana no closed" << std::endl;
            _configuration_dialog->retranslateUi();
        }
    }
    if (_settings_dialog != NULL)
        if (!_settings_dialog->closed)
            _settings_dialog->retranslateUi();
}

//_principal_window->retranslateUi();
//if (_geometries_widget != NULL)
//    if (!_geometries_widget->getClosed() )
//        _geometries_widget->retranslateUi();
//if (_param_widget_uav != NULL)
//    if (!_param_widget_uav->getClosed())
//        _param_widget_uav->retranslateUi();
//if (_param_widget_conventional != NULL)
//    if (!_param_widget_conventional->getClosed())
//        _param_widget_conventional->retranslateUi();
//if (_configuration_dialog != NULL)
//    if (!_configuration_dialog->getClosed())
//        _configuration_dialog->retranslateUi();
//if (_settings_dialog != NULL)
//    if (!_settings_dialog->closed)
//        _settings_dialog->retranslateUi();
